package modules

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// searchInDirectory 在目录中搜索文件，通过通道实时返回结果
func searchInDirectory(ctx context.Context, rootDir, query, rootName string, resultChan chan<- FileInfo) {
	defer close(resultChan)
	query = strings.TrimSpace(query)
	query, _ = url.QueryUnescape(query)
	hasExtension := strings.Contains(query, ".")
	var ext string
	if hasExtension {
		parts := strings.SplitN(query, ".", 2)
		query = strings.ToLower(parts[0])
		ext = strings.ToLower(parts[1])
	} else {
		query = strings.ToLower(query)
	}
	err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
			if err != nil {
				return err
			}
			if hasExtension && info.IsDir() {
				return nil
			}
			filename := info.Name()
			fileNameWithoutExt := strings.ToLower(strings.TrimSuffix(filename, filepath.Ext(filename)))
			fileExt := strings.ToLower(strings.TrimPrefix(filepath.Ext(filename), "."))
			if hasExtension {
				if IsFileAllowed(filename) {
					if strings.Contains(fileNameWithoutExt, query) && fileExt == ext {
						item := GetFileInfo(path, rootName)
						select {
						case <-ctx.Done():
							return ctx.Err()
						case resultChan <- item:
						}
					}
				}
			} else {
				if strings.Contains(strings.ToLower(filename), query) || (info.IsDir() && strings.Contains(strings.ToLower(info.Name()), query)) {
					item := GetFileInfo(path, rootName)
					select {
					case <-ctx.Done():
						return ctx.Err()
					case resultChan <- item:
					}
				}
			}
			return nil
		}
	})
	if err != nil && err != context.Canceled {
		log.Printf("在目录 %s 中搜索文件时出错: %v", rootDir, err)
	}
}

// SearchFiles 搜索文件
func SearchFiles(w http.ResponseWriter, r *http.Request) {
	PrintRequestInfo(r)
	query := strings.TrimPrefix(r.URL.Path, "/search/")
	query, _ = url.QueryUnescape(query)
	w.Header().Set("Content-Type", "text/event-stream")

	// 创建可取消的 context
	ctx, cancel := context.WithCancel(r.Context())
	// 监听客户端断开连接
	notify := w.(http.CloseNotifier).CloseNotify()
	go func() {
		<-notify
		cancel() // 客户端断开连接时取消 context
	}()

	resultChan := make(chan FileInfo)
	var wg sync.WaitGroup

	// 为每个根目录启动搜索 goroutine
	for _, rootDir := range config.RootDirs {
		rootName := filepath.Base(rootDir)
		wg.Add(1)
		go func(ctx context.Context, dir, q, name string) {
			defer wg.Done()
			dirResultChan := make(chan FileInfo)
			// 将 context 传递给 searchInDirectory
			go searchInDirectory(ctx, dir, q, name, dirResultChan)
			for item := range dirResultChan {
				select {
				case <-ctx.Done():
					return
				case resultChan <- item:
				}
			}
		}(ctx, rootDir, query, rootName)
	}

	// 启动一个 goroutine 在所有搜索完成后关闭通道
	go func() {
		wg.Wait()
		close(resultChan)
	}()

	var totalCount int
	// 从通道接收结果并发送给客户端
	for {
		select {
		case <-ctx.Done():
			// 客户端断开连接，直接返回
			return
		case item, ok := <-resultChan:
			if !ok {
				// 通道已关闭，发送搜索完成消息
				data, _ := json.Marshal(map[string]interface{}{
					"success": true,
					"message": fmt.Sprintf("搜索完成，共找到 %d 个结果", totalCount),
					"data":    []interface{}{},
				})
				fmt.Fprintf(w, "data: %s\n\n", data)
				if f, ok := w.(http.Flusher); ok {
					f.Flush()
				}
				return
			}
			totalCount++
			if totalCount > 1000 {
				cancel() // 超过 1000 条结果，取消搜索
				data, _ := json.Marshal(map[string]interface{}{
					"success": true,
					"message": "检索结果超过 1000，中止检索",
					"data":    []interface{}{},
				})
				fmt.Fprintf(w, "data: %s\n\n", data)
				if f, ok := w.(http.Flusher); ok {
					f.Flush()
				}
				return
			}
			data, _ := json.Marshal(map[string]interface{}{
				"success": true,
				"message": "",
				"data":    []FileInfo{item},
			})
			fmt.Fprintf(w, "data: %s\n\n", data)
			if f, ok := w.(http.Flusher); ok {
				f.Flush()
			}
		}
	}
}
